home *** CD-ROM | disk | FTP | other *** search
/ Light ROM 1 / LIGHT-ROM 1 (Amiga Library Services)(1994).iso / ffdisks / d910.lha / DSound / DSound.c < prev    next >
C/C++ Source or Header  |  1993-08-28  |  22KB  |  833 lines

  1.  
  2. /**************************************************************************/
  3. /*                 DSound V1.30                  */
  4. /*     Copyright 1991-1993 by Dave Schreiber, All Rights Reserved      */
  5. /*                                      */
  6. /* To compile with SAS/C version 6, type:                  */
  7. /*    smake                                  */
  8. /*                                      */
  9. /* Revision history:                              */
  10. /*    V1.30  - DSound now displays the name of the sound sample being      */
  11. /*           played, the number of seconds of the sample that have been */
  12. /*           played, and the total number of seconds in the sample.      */
  13. /*           A bug that prevent DSound from being aborted from the      */
  14. /*           window when a stereo sample is played has also been fixed. */
  15. /*           July 17, 1993                          */
  16. /*    V1.20  - Added the ability to stop DSound by typing CTRL-C, and      */
  17. /*           added the switch '-w', which keeps the DSound window from  */
  18. /*           opening.                           */
  19. /*           August 23, 1992                          */
  20. /*    V1.10  - Added the ability to play a sound sample repeatedly (in a  */
  21. /*           loop).                              */
  22. /*           July 11, 1992                          */
  23. /*    V1.00  - Added a new module (Mem.c) which allows a sample to be     */
  24. /*           loaded entirely into memory, so samples can be played from */
  25. /*           floppy disk without first copying to a hard or RAM drive.  */
  26. /*           DSound also can now play a single channel of a stereo      */
  27. /*           out of two speakers.  The small window, used to let the      */
  28. /*           user abort a playing sample, as been redone (DSound also   */
  29. /*           now responds instantly when the user clicks on the Close   */
  30. /*           gadget).  DSound now checks a given 8SVX sample to make      */
  31. /*           sure that it is actually a valid sample.  Finally, DSound  */
  32. /*           has been made pure (residentiable).                        */
  33. /*           Second release (April 16, 1992)                            */
  34. /*    V0.94a - Can now play a mono sample out of both speakers at the      */
  35. /*           same time (using the -2 switch).                           */
  36. /*           March 27, 1992 (a little later)                            */
  37. /*    V0.93a - Now handles stereo sound samples.  Either the right or      */
  38. /*           left, or both, stereo channels can be played.  Also split  */
  39. /*           off the code that actually plays the sound sample into a   */
  40. /*           separate source file (Play.c).                             */
  41. /*           March 27, 1992                          */
  42. /*    V0.92a - Now gets the length of the sound sample from the head of   */
  43. /*           the BODY chunk, instead of the VHDR (a workaround to a bug */
  44. /*           in the Perfect Sound software that would sometimes store   */
  45. /*           an incorrect length in the VHDR chunk of a sound sample).  */
  46. /*           November 4, 1991                       */
  47. /*    V0.91a - First release (September 11, 1991)                         */
  48. /**************************************************************************/
  49.  
  50. #include <exec/types.h>
  51. #include <exec/exec.h>
  52. #include <devices/audio.h>
  53. #include <dos/dos.h>
  54. #include <intuition/intuition.h>
  55. #include <intuition/intuitionbase.h>
  56. #include <graphics/gfxbase.h>
  57. #include <stdlib.h>
  58. #include <stdio.h>
  59. #include <string.h>
  60.  
  61. #include "dsound.h"
  62.  
  63. #include <proto/intuition.h>
  64. #include <proto/graphics.h>
  65. #include <proto/exec.h>
  66. #include <proto/dos.h>
  67.  
  68. char filename[256];
  69.  
  70. #define DEF_BUF_SIZE 0xFFFFFFFF
  71.  
  72. void InterpretArgs(int argc,char *argv[]);
  73. BOOL noFilter=FALSE;
  74. UBYTE volume=0;
  75. UWORD speed=0;
  76. ULONG bufSize=DEF_BUF_SIZE;
  77.  
  78. void filter_on(void);
  79. void filter_off(void);
  80. char *getDoubleDigit(unsigned int value,char *buf);
  81.  
  82. char *version="$VER: DSound V1.30 (17.7.93)";
  83. char *copyright="Copyright 1991-1992 by Dave Schreiber, All Rights Reserved";
  84.  
  85. struct IntuitionBase *IntuitionBase=NULL;
  86. struct GfxBase *GfxBase=NULL;
  87.  
  88. struct Window *window=NULL;
  89.  
  90. BPTR file=NULL;
  91.  
  92. channel audioChannel=UNSPECIFIED;
  93. BOOL bothChan=FALSE;
  94. BOOL readAll=FALSE;
  95. BOOL loop=FALSE;
  96. BOOL titleBarName=TRUE;
  97. BOOL titleBarTime=TRUE;
  98.  
  99. /*The window definition*/
  100. struct NewWindow newWindow = {
  101.     0,0,
  102.     60,56,
  103.     0,1,
  104.     CLOSEWINDOW,
  105.     SMART_REFRESH|WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE,
  106.     NULL,
  107.     NULL,
  108.     "DSound V1.30",
  109.     NULL,
  110.     NULL,
  111.     5,5,
  112.     640,200,
  113.     WBENCHSCREEN
  114. };
  115.  
  116. /*This determines whether or not the window will be opened*/
  117. BOOL openTheWdw=TRUE;
  118. ULONG signalMask=SIGBREAKF_CTRL_C;
  119.  
  120. struct TextFont *titleBarFont=NULL;
  121.  
  122. main(int argc,char *argv[])
  123. {
  124.    struct Voice8Header vhdr;
  125.    UBYTE foo2[5];
  126.    UBYTE foo[5];
  127.    ULONG chan;
  128.    ULONG sampleLength;
  129.    ULONG lock;
  130.    ULONG titleLength,nameLength,timeLength,colonLength,finalDelta;
  131.    char *chanStr;
  132.  
  133.    filename[0]=NULL;
  134.  
  135.    /*Get and interpret the command-line arguments*/
  136.    InterpretArgs(argc,argv);
  137.  
  138.    /*Exit if there was no sound sample specified*/
  139.    if(filename[0]==NULL)
  140.    {
  141.       WriteMsg("Please specify the name of a sound sample\n");
  142.       cleanup(75);
  143.    }
  144.  
  145.    /*Open the file*/
  146.    file=Open(filename,MODE_OLDFILE);
  147.    if(file==NULL)
  148.    {
  149.       WriteMsg("Couldn't open the file\n");
  150.       cleanup(100);
  151.    }
  152.  
  153.    /*If the user hasn't told us not to open the window*/
  154.  
  155.    if(openTheWdw)
  156.    {
  157.       char temp[256];
  158.       /*Open libraries*/
  159.       GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",0L);
  160.       IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",0L);
  161.  
  162.       if(GfxBase==NULL || IntuitionBase==NULL)
  163.       {
  164.      WriteMsg("A shared library could not be opened\n");
  165.      cleanup(50);
  166.       }
  167.  
  168.       /*Get the size of the title bar font in a rather illegal way        */
  169.       /*Note:  programmers at C= should put a GetDefTitleBarFontHeight()    */
  170.       /*function into Intuition before complaining to me about the following*/
  171.       /*code.                                    */
  172.  
  173.       lock=LockIBase(0L);
  174.       newWindow.Height=IntuitionBase->ActiveScreen->Font->ta_YSize+3;
  175.       UnlockIBase(lock);
  176.  
  177.       window=OpenWindow(&newWindow);
  178.  
  179.       if(window==NULL)
  180.      cleanup(110);
  181.       signalMask|=1<<window->UserPort->mp_SigBit;
  182.  
  183.       titleBarFont=OpenFont(IntuitionBase->ActiveScreen->Font);
  184.       if(titleBarFont==NULL)
  185.      cleanup(115);
  186.  
  187.       SetFont(window->RPort,titleBarFont);
  188.       finalDelta=titleLength=TextLength(window->RPort,"DSound V1.30",12);
  189.       colonLength=TextLength(window->RPort,":  ",3);
  190.       if(titleBarTime==FALSE)
  191.       {
  192.      timeLength=0;
  193.      if(titleBarName==FALSE)
  194.         colonLength=0;
  195.       }
  196.       else
  197.      timeLength=TextLength(window->RPort,"(00:00/00:00) ",14);
  198.  
  199.       if(titleBarName==FALSE)
  200.      nameLength=0;
  201.       else
  202.       {
  203.      strcpy(temp,"\"\"");
  204.      strcat(temp,filename);
  205.      nameLength=TextLength(window->RPort,temp,strlen(temp));
  206.       }
  207.  
  208.       if(60+finalDelta+nameLength+colonLength+timeLength >= window->WScreen->Width)
  209.       {
  210.      titleBarName=FALSE;
  211.      if(60+finalDelta+colonLength+timeLength >= window->WScreen->Width)
  212.      {
  213.         titleBarTime=FALSE;
  214.         if(60+titleLength >= window->WScreen->Width)
  215.            cleanup(199);
  216.      }
  217.      else
  218.         finalDelta+=(colonLength+timeLength);
  219.       }
  220.       else
  221.      finalDelta+=(colonLength+timeLength+nameLength);
  222.  
  223.       SizeWindow(window,finalDelta,0);
  224.    }
  225.  
  226.    /*Read the header*/
  227.    Read(file,foo,4);
  228.    Seek(file,4,OFFSET_CURRENT);
  229.    Read(file,foo2,4);
  230.  
  231.    foo[4]=foo2[4]=NULL;
  232.  
  233.    /*Check the header's validity, more or less*/
  234.    if((strcmp(foo,"FORM")!=0) || (strcmp(foo2,"8SVX")!=0))
  235.    {
  236.       WriteMsg("Not a valid IFF 8SVX sound sample file.\n");
  237.       cleanup(120);
  238.    }
  239.  
  240.    if(strcmp(FindChunk(file,"VHDR"),"VHDR")!=0)
  241.    {
  242.       WriteMsg("Couldn't find the 8SVX header (VHDR).\n");
  243.       cleanup(130);
  244.    }
  245.  
  246.    /*Skip past the chunk size*/
  247.    Seek(file,4,OFFSET_CURRENT);
  248.  
  249.    /*Get the VHDR*/
  250.    Read(file,&vhdr,sizeof(struct Voice8Header));
  251.  
  252.    /*If no buffer size was specified, use a buffer that can hold 1 second*/
  253.    /*of sound*/
  254.    if(bufSize==0xFFFFFFFF)
  255.       bufSize=vhdr.samplesPerSec;
  256.  
  257.    /*Check for compression*/
  258.    if(vhdr.sCompression!=0)
  259.    {
  260.       WriteMsg("Can't play a compressed sample!\n");
  261.       cleanup(400);
  262.    }
  263.  
  264.    /*Get the CHAN chunk (which will tell us if the sample is stereo, or,*/
  265.    /*if it is mono, which speaker it should be played out of*/
  266.    chanStr=FindChunk(file,"CHAN");
  267.    if(strcmp(chanStr,"CHAN")==0)
  268.    {
  269.       /*Skip past chunk size*/
  270.       Seek(file,4,OFFSET_CURRENT);
  271.       Read(file,&chan,sizeof(long));
  272.  
  273.       /*The information we're looking for consists of one longword*/
  274.       switch(chan)
  275.       {
  276.      case 2:  /*Mono sample, left speaker*/
  277.         if(bothChan)
  278.            /*Play out of both channels if -2 used*/
  279.            audioChannel=MONO_BOTH;
  280.         else
  281.            if(audioChannel==UNSPECIFIED)
  282.           audioChannel=MONO_LEFT;
  283.         break;
  284.      case 4:  /*Mono sample, right speaker*/
  285.         if(bothChan)
  286.            /*Play out of both channels if -2 used*/
  287.            audioChannel=MONO_BOTH;
  288.         else
  289.            if(audioChannel==UNSPECIFIED)
  290.           audioChannel=MONO_RIGHT;
  291.         break;
  292.      case 6:     /*Stereo*/
  293.         switch(audioChannel)
  294.         {
  295.            /*This reconciles a user's choice with the fact that the*/
  296.            /*sample is in stereo*/
  297.  
  298.            /*Play left stereo channel*/
  299.            case MONO_LEFT:
  300.           if(bothChan)
  301.              audioChannel=STEREO_LEFT_BOTH;
  302.           else
  303.              audioChannel=STEREO_LEFT;
  304.           break;
  305.  
  306.            /*Play right stereo channel*/
  307.            case MONO_RIGHT:
  308.           if(bothChan)
  309.              audioChannel=STEREO_RIGHT_BOTH;
  310.           else
  311.              audioChannel=STEREO_RIGHT;
  312.           break;
  313.  
  314.            /*Play both channels*/
  315.            case UNSPECIFIED:
  316.           audioChannel=STEREO;
  317.           break;
  318.         }
  319.         break;
  320.       }
  321.  
  322.       /*Find the start of the BODY chunk*/
  323.       chanStr=FindChunk(file,"BODY");
  324.    }
  325.    else
  326.    {
  327.       chan=0;
  328.       if(bothChan)
  329.      audioChannel=MONO_BOTH;
  330.    }
  331.  
  332.    if(strcmp(chanStr,"BODY")!=0)
  333.    {
  334.       WriteMsg("Couldn't find body of sample.\n");
  335.       cleanup(140);
  336.    }
  337.  
  338.    if(noFilter)
  339.       filter_off();
  340.  
  341.    /*Get the length of the sample*/
  342.    Read(file,(char *)&sampleLength,4);
  343.  
  344.    SetSignal(0,0);
  345.  
  346.    /*Play the sample by choosing the appropriate player function*/
  347.    switch(audioChannel)
  348.    {
  349.       case MONO_LEFT:
  350.       case MONO_RIGHT:
  351.       case UNSPECIFIED:
  352.      /*Simple mono playback*/
  353.      playMonoSample(file,audioChannel,&vhdr,sampleLength);
  354.      break;
  355.       case MONO_BOTH:
  356.      /*Mono playback using both speakers*/
  357.      playMonoTwice(file,audioChannel,&vhdr,sampleLength);
  358.      break;
  359.       case STEREO_RIGHT:
  360.      /*Right stereo channel*/
  361.      audioChannel=MONO_RIGHT;
  362.      Seek(file,sampleLength/2,OFFSET_CURRENT);
  363.      playMonoSample(file,audioChannel,&vhdr,sampleLength/2);
  364.      break;
  365.       case STEREO_RIGHT_BOTH:
  366.      /*Right stereo channel out of both speakers*/
  367.      audioChannel=MONO_RIGHT;
  368.      Seek(file,sampleLength/2,OFFSET_CURRENT);
  369.      playMonoTwice(file,audioChannel,&vhdr,sampleLength/2);
  370.      break;
  371.       case STEREO_LEFT:
  372.      /*Left stereo channel*/
  373.      audioChannel=MONO_LEFT;
  374.      playMonoSample(file,audioChannel,&vhdr,sampleLength/2);
  375.      break;
  376.       case STEREO_LEFT_BOTH:
  377.      /*Left stereo channel out of both speakers*/
  378.      audioChannel=MONO_LEFT;
  379.      playMonoTwice(file,audioChannel,&vhdr,sampleLength/2);
  380.      break;
  381.       case STEREO:
  382.      /*Stereo sample (both channels)*/
  383.      playStereoSample(file,audioChannel,&vhdr,sampleLength/2,filename);
  384.      break;
  385.    }
  386.  
  387.    if(noFilter)
  388.       filter_on();
  389.  
  390.    /*Free allocated resources and exit*/
  391.    cleanup(0);
  392. }
  393.  
  394.  
  395.  
  396. /* Get an audio channel */
  397. struct IOAudio *GetAudioChannel(ULONG bufferSize,UBYTE *allocationMap)
  398. {
  399.    struct IOAudio *aIOB;
  400.    void *audioBuf;
  401.    struct Port *aPort;
  402.  
  403.    aPort=(struct Port *)CreatePort("dsound",0);
  404.    if(aPort==NULL)
  405.       return(NULL);
  406.  
  407.    /* Allocate the chip memory buffer for the channel */
  408.    audioBuf=(void *)AllocMem(bufferSize,MEMF_CHIP);
  409.    if(audioBuf==NULL)
  410.    {
  411.       DeletePort((struct MsgPort *)aPort);
  412.       return(NULL);
  413.    }
  414.  
  415.    /* Allocate an IOAudio structure*/
  416.    aIOB=(struct IOAudio *)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR);
  417.    if(aIOB==NULL)
  418.    {
  419.       DeletePort((struct MsgPort *)aPort);
  420.       FreeMem(audioBuf,bufferSize);
  421.       return(NULL);
  422.    }
  423.  
  424.    /* Set up the IOAudio to allocate the command channel */
  425.    aIOB->ioa_Request.io_Message.mn_Node.ln_Pri=0;
  426.    aIOB->ioa_Request.io_Message.mn_ReplyPort=(struct MsgPort *)aPort;
  427.  
  428.    aIOB->ioa_Data=allocationMap;
  429.    aIOB->ioa_Length=4;
  430.    aIOB->ioa_Request.io_Command=ADCMD_ALLOCATE;
  431.  
  432.    /*Open the audio device*/
  433.    OpenDevice("audio.device",0,(struct IORequest *)aIOB,0);
  434.  
  435.  
  436.    if(aIOB->ioa_AllocKey==0)
  437.    {  /*There was an error*/
  438.       DeletePort((struct MsgPort *)aPort);
  439.       FreeMem(audioBuf,bufferSize);
  440.       FreeMem(aIOB,sizeof(struct IOAudio));
  441.       return(NULL);
  442.    }
  443.    else
  444.    {
  445.       /* Set up the IOAudio for writes */
  446.       aIOB->ioa_Request.io_Command=CMD_WRITE;
  447.       aIOB->ioa_Request.io_Flags=ADIOF_PERVOL;
  448.       aIOB->ioa_Data=audioBuf;
  449.       aIOB->ioa_Length=bufferSize;
  450.       return(aIOB);
  451.    }
  452. }
  453.  
  454. /* Free an allocated audio channel */
  455. void FreeAudioChannel(struct IOAudio *aIOB)
  456. {
  457.    if(aIOB==NULL)
  458.       return;
  459.  
  460.    /* Free the audi obuffer */
  461.    if(aIOB->ioa_Data!=NULL)
  462.       FreeMem(aIOB->ioa_Data,aIOB->ioa_Length);
  463.  
  464.    /* Free the audio channel */
  465.    aIOB->ioa_Request.io_Command=ADCMD_FREE;
  466.    BeginIO((struct IORequest *)aIOB);
  467.    WaitIO((struct IORequest *)aIOB);
  468.    DeletePort(aIOB->ioa_Request.io_Message.mn_ReplyPort);
  469.  
  470.    /* Close the audio channel */
  471.    CloseDevice((struct IORequest *)aIOB);
  472.  
  473.    /* Free the IOAudio structure */
  474.    FreeMem(aIOB,sizeof(struct IOAudio));
  475.    return;
  476. }
  477.  
  478. /* Initialize an IOAudio's volume, period, and set the number of cycles */
  479. /* to one */
  480. void InitAudioChannel(struct IOAudio *aIOB,UWORD volume,UWORD period)
  481. {
  482.    aIOB->ioa_Period=period;
  483.    aIOB->ioa_Volume=volume;
  484.    aIOB->ioa_Cycles=1;
  485.    return;
  486. }
  487.  
  488. /* Duplicate an IOAudio structure */
  489. struct IOAudio *DuplicateAudioChannel(struct IOAudio *OrigIOB)
  490. {
  491.    struct IOAudio *aIOB;
  492.    void *audioBuf;
  493.  
  494.    if(OrigIOB==NULL)
  495.       return(NULL);
  496.  
  497.    /* Allocate the alternate buffer */
  498.    audioBuf=(void *)AllocMem(OrigIOB->ioa_Length,MEMF_CHIP);
  499.    if(audioBuf==NULL)
  500.       return(NULL);
  501.  
  502.    /*Allocate the IOAudio structure*/
  503.    aIOB=(struct IOAudio *)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR);
  504.    if(aIOB==NULL)
  505.    {
  506.       FreeMem(audioBuf,OrigIOB->ioa_Length);
  507.       return(NULL);
  508.    }
  509.  
  510.    /*Copy the original IOAudio's contents to the new one*/
  511.    CopyMem(OrigIOB,aIOB,sizeof(struct IOAudio));
  512.  
  513.    /*Except for the buffer pointer, of course*/
  514.    aIOB->ioa_Data=audioBuf;
  515.  
  516.    return(aIOB);
  517. }
  518.  
  519. /*Delete a duplicated IOAudio*/
  520. void DeleteDuplication(struct IOAudio *aIOB)
  521. {
  522.    if(aIOB != NULL)
  523.    {
  524.       /* Free the memory for the buffer and IOAudio */
  525.       if(aIOB->ioa_Data != NULL)
  526.      FreeMem(aIOB->ioa_Data,aIOB->ioa_Length);
  527.       FreeMem(aIOB,sizeof(struct IOAudio));
  528.    }
  529.    return;
  530. }
  531.  
  532. /* Load an IOAudio's buffer from an open file */
  533. ULONG LoadAudioBuffer(BPTR file,struct IOAudio *aIOB,ULONG toRead)
  534. {
  535.    if(toRead==0)
  536.       return(0);
  537.  
  538.    if(file==0L)
  539.       getLeft(aIOB->ioa_Data);
  540.    else if(file==4L)
  541.       getRight(aIOB->ioa_Data);
  542.    else
  543.       aIOB->ioa_Length=Read(file,aIOB->ioa_Data,toRead);
  544.    return(aIOB->ioa_Length);
  545. }
  546.  
  547. /*Find the beginning of an IFF chunk.  This routine will search for that*/
  548. /*chunk's name, and if found, will leave the file cursor at the chunk size*/
  549. /*field.  If the chunk isn't found, the file cursor will be left at the*/
  550. /*size field of the BODY chunk, if there was one*/
  551. char *FindChunk(BPTR file,char *string)
  552. {
  553.    static char buf[5];
  554.    long len,actLen;
  555.    buf[4]=NULL;
  556.  
  557.    actLen=Read(file,buf,4);
  558.    while(strcmp(string,buf)!=0 && strcmp(buf,"BODY")!=0 && actLen > 0)
  559.    {
  560.       Read(file,(char *)&len,4);
  561.       Seek(file,len,OFFSET_CURRENT);
  562.       actLen=Read(file,buf,4);
  563.    }
  564.    return(buf);
  565. }
  566.  
  567. /* Interpret the command line arguments */
  568. void InterpretArgs(int argc,char *argv[])
  569. {
  570.    int i;
  571.  
  572.    for(i=1;i<argc;i++)
  573.    {
  574.       if(argv[i][0]=='-')
  575.      switch(argv[i][1])
  576.      {
  577.         /*Deactivate title bar filename*/
  578.         case 'n':
  579.         case 'N':
  580.            titleBarName=FALSE;
  581.            break;
  582.  
  583.         /*Deactivate title bar time*/
  584.         case 't':
  585.         case 'T':
  586.            titleBarTime=FALSE;
  587.            break;
  588.  
  589.         /* Read the entire sample into memory before playing */
  590.         case 'm':
  591.         case 'M':
  592.            readAll=TRUE;
  593.            break;
  594.  
  595.         /* Use the left channel */
  596.         case 'l':
  597.         case 'L':
  598.            audioChannel=MONO_LEFT;
  599.            break;
  600.  
  601.         /* Use the right channel */
  602.         case 'r':
  603.         case 'R':
  604.            audioChannel=MONO_RIGHT;
  605.            break;
  606.  
  607.         /*Play a mono sample out of both speakers*/
  608.         case '2':
  609.            bothChan=TRUE;
  610.            break;
  611.  
  612.         /* Switch off the low-pass filter while the sample is playing */
  613.         case 'f':
  614.         case 'F':
  615.            noFilter=TRUE;
  616.            break;
  617.  
  618.         /* Play a sample at a given speed */
  619.         case 's':
  620.         case 'S':
  621.            speed=atol(&argv[i][2]);
  622.            if(speed > 28000)
  623.           speed=0;
  624.            break;
  625.  
  626.         /* The volume at which the sample should be played */
  627.         case 'v':
  628.         case 'V':
  629.            volume=atol(&argv[i][2]);
  630.            if(volume > 64)
  631.           volume=0;
  632.            break;
  633.  
  634.         /* The size of the chip RAM buffers */
  635.         case 'b':
  636.         case 'B':
  637.            bufSize=(atol(&argv[i][2])+1)&(~1);
  638.            if(bufSize==0)
  639.           bufSize=DEF_BUF_SIZE;
  640.            break;
  641.  
  642.         /* Loop the sample */
  643.         case 'o':
  644.         case 'O':
  645.            loop=TRUE;
  646.            break;
  647.  
  648.         case 'w':
  649.         case 'W':
  650.            openTheWdw=FALSE;
  651.            break;
  652.      }
  653.       else if(argv[i][0]=='?')
  654.       {
  655.      /*On-line help*/
  656.      WriteMsg("DSound V1.30 ©1991-1993 by Dave Schreiber\n");
  657.      WriteMsg("Usage:\n");
  658.      WriteMsg("  DSound <options> <filename>\n");
  659.      WriteMsg("Where the options are:\n");
  660.      WriteMsg("  -l -- Play the sample using the left speaker\n");
  661.      WriteMsg("  -r -- Play the sample using the right speaker\n");
  662.      WriteMsg("  -2 -- Play the sample using both speakers\n");
  663.      WriteMsg("  -f -- Shut off the low-pass filter\n");
  664.      WriteMsg("  -m -- Load the entire sample into memory\n");
  665.      WriteMsg("  -o -- Play the sample continuously (loop)\n");
  666.      WriteMsg("  -w -- Do not open the DSound window\n");
  667.      WriteMsg("  -n -- Do not show the sample name in the window\n");
  668.      WriteMsg("  -t -- Do not show the sample times in the window\n");
  669.      WriteMsg("  -s<speed> -- Play the sample at the given speed (samples/sec)\n");
  670.      WriteMsg("  -v<volume> -- Play the sample at the given volume (0-64)\n");
  671.      WriteMsg("  -b<bufsize> -- Use a buffer of size <bufsize> (default is 30K)\n");
  672.      exit(0);
  673.       }
  674.       else     /*Otherwise, the argument is a filename */
  675.      strcpy(filename,argv[i]);
  676.    }
  677. }
  678.  
  679. /*Update the sample information in the DSound window's title bar*/
  680. /*This information can included the name of the sample, along with*/
  681. /*its length and amount played (both in seconds)*/
  682. void updateSampleInfo(unsigned int currentPos,unsigned int length,
  683.               unsigned int sampleRate)
  684. {
  685.    unsigned int currentSeconds,currentMinutes,totalSeconds,totalMinutes;
  686.    static char windowTitle[256];
  687.    char tempBuf[4][4];
  688.    static BOOL nameAlreadyDisplayed=FALSE;
  689.  
  690.    /*If the user wants neither the name nor time printed, do nothing*/
  691.    /*Also do nothing if the window isn't open*/
  692.    if((titleBarTime==FALSE && titleBarName==FALSE) || window==NULL)
  693.       return;
  694.  
  695.    /*Return if the user just wanted the name displayed, and it has been*/
  696.    if(titleBarTime==FALSE && nameAlreadyDisplayed==TRUE)
  697.       return;
  698.  
  699.    /*Beginning of the title*/
  700.    strcpy(windowTitle,"DSound V1.30:  ");
  701.  
  702.    /*If the user wants the sample name displayed, put it in the buffer*/
  703.    if(titleBarName)
  704.    {
  705.       nameAlreadyDisplayed=TRUE;
  706.       sprintf(&windowTitle[strlen(windowTitle)],"\"%s\" ",filename);
  707.  
  708.       /*The name has been (or will be shortly) displayed, so don't */
  709.       /*update it again if you don't have to */
  710.       nameAlreadyDisplayed=TRUE;
  711.    }
  712.  
  713.    /*Likewise for the time left and the total time*/
  714.    if(titleBarTime)
  715.    {
  716.       /*Get the total time*/
  717.       totalSeconds=(length)/sampleRate;
  718.       totalMinutes=totalSeconds/60;
  719.       totalSeconds-=totalMinutes*60;
  720.  
  721.       /*Get the current time*/
  722.       currentSeconds=(currentPos)/sampleRate;
  723.       currentMinutes=currentSeconds/60;
  724.       currentSeconds-=currentMinutes*60;
  725.  
  726.       /*Create the string that holds the time, and put it in the*/
  727.       /*title bar buffer*/
  728.       sprintf(&windowTitle[strlen(windowTitle)],"(%s:%s/%s:%s)",
  729.              getDoubleDigit(currentMinutes,tempBuf[0]),
  730.              getDoubleDigit(currentSeconds,tempBuf[1]),
  731.              getDoubleDigit(totalMinutes,tempBuf[2]),
  732.              getDoubleDigit(totalSeconds,tempBuf[3]));
  733.    }
  734.    Forbid();
  735.       /*Make sure that the screen isn't locked (e.g. holding down the*/
  736.       /*RMB will lock the screen), so that DSound will continue to */
  737.       /*play even if it can't update the title bar*/
  738.       if(window->WScreen->LayerInfo.Lock.ss_NestCount==0)
  739.      SetWindowTitles(window,windowTitle,NULL);
  740.    Permit();
  741.  
  742.    return;
  743. }
  744.  
  745. char *getDoubleDigit(unsigned int value,char *buf)
  746. {
  747.    if(value<10)
  748.       sprintf(buf,"0%d",value);
  749.    else
  750.       sprintf(buf,"%d",value);
  751.  
  752.    return(buf);
  753. }
  754.  
  755. /*Switch on the low-pass filter */
  756. void filter_on()
  757. {
  758.    *((char *)0x0bfe001)&=0xFD;
  759. }
  760.  
  761. /*Switch off the low-pass filter*/
  762. void filter_off()
  763. {
  764.    *((char *)0x0bfe001)|=0x02;
  765. }
  766.  
  767. /*Write a message to the CLI*/
  768. void WriteMsg(char *errMsg)
  769. {
  770.    Write(Output(),errMsg,strlen(errMsg));
  771. }
  772.  
  773. /*Take a file handle and that handle's filename, and open that file again*/
  774. /*The position in the second file in set to the position in the first */
  775. /*file (so that the two file handles are essentially identical)*/
  776. /*This requires that the first file was opened in a shared mode, like */
  777. /*MODE_OLDFILE*/
  778. BPTR dupFileHandle(BPTR origFile,char *filename)
  779. {
  780.    BPTR dupFile;
  781.  
  782.    dupFile=Open(filename,MODE_OLDFILE);
  783.  
  784.    if(dupFile==NULL)
  785.       return(NULL);
  786.  
  787.    Seek(dupFile,getPosInFile(origFile),OFFSET_BEGINNING);
  788.    return(dupFile);
  789. }
  790.  
  791. /*Get the current position in a file*/
  792. ULONG getPosInFile(BPTR file)
  793. {
  794.    LONG position;
  795.  
  796.    position=Seek(file,0,OFFSET_CURRENT);
  797.    return((ULONG)position);
  798. }
  799.  
  800. /* Free allocated resources */
  801. void cleanup(int err)
  802. {
  803.    /*If the entire sample was read into memory, this will delete whatever*/
  804.    /*part of the sample still remains in memory*/
  805.    deleteLeft();
  806.    deleteRight();
  807.  
  808.    if(file!=NULL)
  809.       Close(file);
  810.  
  811.    if(window!=NULL)
  812.       CloseWindow(window);
  813.  
  814.    if(titleBarFont!=NULL)
  815.       CloseFont(titleBarFont);
  816.  
  817.    if(GfxBase!=NULL)
  818.       CloseLibrary((struct Library *)GfxBase);
  819.  
  820.    if(IntuitionBase!=NULL)
  821.       CloseLibrary((struct Library *)IntuitionBase);
  822.  
  823.    exit(err);
  824. }
  825.  
  826. #ifdef LATTICE
  827. int CXBRK(void) {return(0);}
  828. int chkabort(void) {return(0);}
  829. #endif
  830.  
  831. /*End of DSound.c*/
  832.  
  833.